package com.zjjk.transfer.app;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.geekidea.springbootplus.framework.common.service.BaseService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.stream.Collectors;

public abstract class BaseTransfer<S extends BaseEntity, T extends BaseEntity, SS extends BaseService<S>, TS extends BaseService<T>> implements Transfer {
    
    private static final int BATCH_MAX_SIZE = 1000;
    
    @Autowired
    protected SS sourceService;
    
    @Autowired
    protected TS targetService;
    
    // private Constructor<?> targetConstructor;
    //
    //
    // {
    //     Class<?> clazz = this.getClass();
    //     Type type = clazz.getGenericSuperclass();
    //     if (type instanceof ParameterizedType) {
    //         Type[] p = ((ParameterizedType) type).getActualTypeArguments();
    //         Class<?> targetClass = (Class<T>) p[1];
    //         Constructor<?>[] constructors = targetClass.getConstructors();
    //         targetConstructor = constructors[0];
    //     }
    // }
    
    @Override
    public void trans() {
        int count = sourceService.count();
        if (count < BATCH_MAX_SIZE) {
            List<S> sources = sourceService.list();
            transBatch(sources);
        } else {
            for (int i = 0; i < count; i++) {
                LambdaQueryWrapper<S> wrapper = new LambdaQueryWrapper<>();
                int offset = i * BATCH_MAX_SIZE;
                String limit = String.format("limit %s,%s", offset, BATCH_MAX_SIZE);
                wrapper.last(limit);
                List<S> sources = sourceService.list(wrapper);
                transBatch(sources);
            }
        }
    }
    
    protected void transBatch(List<S> sources) {
        List<T> targets = sources.stream()
                .map(this::convert)
                .filter(a -> a != null)
                .collect(Collectors.toList());
        this.targetService.saveBatch(targets);
    }
    
    protected abstract T convert(S source);
    
}
